# -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp.osv import fields, osv
from openerp.tools.translate import _
import time
from openerp.tools import float_compare, DEFAULT_SERVER_DATETIME_FORMAT
from openerp import netsvc
import openerp.addons.decimal_precision as dp
from datetime import date, datetime
from openerp import SUPERUSER_ID
from openerp import api
from shutil import move

class stock_picking(osv.osv):

    _inherit = "stock.picking"
    
    def gatepass_print(self, cr, uid, ids, context=None):
        if context is None:
           context = {}
        data = self.read(cr, uid, ids)[0]
        self_browse = self.browse(cr, uid, ids)
        
        datas = {
            'ids': [data.get('id')],
            'model': 'stock.picking',
            'form': data
            }
        return {
            'type': 'ir.actions.report.xml',
            'report_name': 'batam_fast_module.ami_gatepass',
            'datas': datas,
            'name': self_browse.name
            }
    
    def check_today_home_curr(self, cr, uid, picking, context=None):
        
        res_curr_rate_obj = self.pool.get("res.currency.rate")
        
        cur_date = time.strftime("%Y-%m-%d")
        grn_currency_id = grn_currency_name = ''
        
        for grn in self.browse(cr, uid, picking, context=context):
            if grn.picking_type_id.code == 'incoming':
                cr.execute(
                        "select pp.currency_id as grn_curr_id, rc.name as grn_curr_name from purchase_order po " \
                        "left join purchase_order_line pol on pol.order_id = po.id " \
                        "left join stock_move sm on sm.purchase_line_id = pol.id " \
                        "left join stock_picking sp on sm.picking_id = sp.id " \
                        "left join product_pricelist pp on po.pricelist_id = pp.id " \
                        "left join res_currency rc on pp.currency_id = rc.id " \
                        "where sp.id = %s ", \
                        (grn.id,))
            elif grn.picking_type_id.code == 'outgoing':
                cr.execute(
                        "select pp.currency_id as grn_curr_id, rc.name as grn_curr_name from sale_order so " \
                        "left join sale_order_line sol on sol.order_id = so.id " \
                        "left join procurement_order pr on pr.sale_line_id = sol.id " \
                        "left join stock_move sm on sm.procurement_id = pr.id " \
                        "left join stock_picking sp on sm.picking_id = sp.id " \
                        "left join product_pricelist pp on so.pricelist_id = pp.id " \
                        "left join res_currency rc on pp.currency_id = rc.id " \
                        "where sp.id = %s ", \
                        (grn.id,))
            qry = cr.dictfetchall()
            if qry:
                for r in qry:
                    grn_currency_id = r['grn_curr_id']
                    grn_currency_name = r['grn_curr_name']

            home_curr_id = grn.company_id.currency_id.id
            if grn_currency_id <> home_curr_id:
                res_currency_home_ids = res_curr_rate_obj.search(cr, uid, [('currency_id', '=', grn_currency_id), ('name', '>=', cur_date + ' 00:00:00'), ('name', '<=', datetime.now().strftime('%Y-%m-%d %H:%M:%S'))], order='name DESC', limit=1)

                if not res_currency_home_ids:
                    raise osv.except_osv(_('Warning!'), _('Please input today %s currency rate before proceed') % (grn_currency_name,))
            
        return True
    
    @api.cr_uid_ids_context
    def do_enter_transfer_details(self, cr, uid, picking, context=None):
        if not context:
            context = {}
        
        context.update({
            'active_model': self._name,
            'active_ids': picking,
            'active_id': len(picking) and picking[0] or False
        })
        
        self.check_today_home_curr(cr, uid, picking, context=context)
        
        created_id = self.pool['stock.transfer_details'].create(cr, uid, {'picking_id': len(picking) and picking[0] or False}, context)
        return self.pool['stock.transfer_details'].wizard_view(cr, uid, created_id, context)
    
    def action_confirm_int(self, cr, uid, ids, context=None):
        todo = []
        todo_force_assign = []
        for picking in self.browse(cr, uid, ids, context=context):
            todo_force_assign.append(picking.id)
            for r in picking.move_lines:
                if r.state == 'draft':
                    todo.append(r.id)
        if len(todo):
            self.pool.get('stock.move').action_confirm(cr, uid, todo, context=context)
 
        if todo_force_assign:
            self.force_assign(cr, uid, todo_force_assign, context=context)
        return True

    def action_internal_done(self, cr, uid, ids, context=None):
        analytic_line_obj = self.pool.get('analytic.quotation.line')
        product_uom_obj = self.pool.get('product.uom')
        spo_obj = self.pool.get('stock.pack.operation')
        error = ''
        
        for picking in self.browse(cr, uid, ids, context=context):
            if picking.state in ('cancel'):
                continue
            prod_ids = {}
            
            if not picking.project_id2:
                processed_ids = []
                packops2 = spo_obj.search(cr, uid, [('picking_id', '=', picking.id)])
                for packop2 in packops2:
                    spo_obj.unlink(cr, uid, [packop2], context=context)
    
                picking.do_prepare_partial()
                for op in picking.pack_operation_ids:
                    pack_datas = {
                        'product_id': op.product_id.id,
                        'product_uom_id': op.product_uom_id.id,
                        'product_qty': op.product_qty,
                        'package_id': op.package_id.id,
                        'lot_id': op.lot_id.id,
                        'location_id': op.location_id.id,
                        'location_dest_id': op.location_dest_id.id,
                        'result_package_id': op.result_package_id.id,
                        'date': picking.date_done or time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
                        'owner_id': op.owner_id.id,
                    }
                    if op.id:
                        op.write(pack_datas)
                        processed_ids.append(op.id)
        
                packops = spo_obj.search(cr, uid, ['&', ('picking_id', '=', picking.id), '!', ('id', 'in', processed_ids)])
                for packop in packops:
                    packop.unlink()
                return self.do_transfer_internal(cr, uid, [picking.id], context=context)
            
            for sm in picking.move_lines:
                #product no found
                analytic_ids = analytic_line_obj.search(cr, uid, [('product_id', '=', sm.product_id.id), \
                                                                 ('analytic_id', '=', picking.project_id2.analytic_account_id.id), \
                                                                 ('type', '=', picking.department), \
                                                                 ], context=context)
                if not analytic_ids:
                    error += ('the product (%s) that entered is not list it at project : %s and department : %s. (No. %s) \n' % (sm.product_id.name, picking.project_id2.name, picking.department, sm.no_stock_move))
                default_uom = sm.product_id.uom_id and sm.product_id.uom_id.id
                q = product_uom_obj._compute_qty(cr, uid, sm.product_uom and sm.product_uom.id, \
                                         sm.product_uom_qty, default_uom)
                sign = 1
                if (sm.location_id.id == picking.picking_type_id.default_location_src_id.id) and  (sm.location_dest_id.id == picking.picking_type_id.default_location_dest_id.id):
                    sign = 1
                elif (sm.location_id.id == picking.picking_type_id.default_location_dest_id.id) and  (sm.location_dest_id.id == picking.picking_type_id.default_location_src_id.id):
                    sign = -1
                else:
                    raise osv.except_osv(_('Error!'), _('Wrong Location Selected!! \n Please Select the correct location for product: %s (No. %s)' %(sm.product_id.name, sm.no_stock_move)))
                original_remaining_qty = 0
                if analytic_ids:
                    analytic_line = analytic_line_obj.browse(cr, uid, analytic_ids[0], context=context)
                    original_remaining_qty = analytic_line.real_qty - analytic_line.process_qty
                if sm.product_id.id not in prod_ids:
                    prod_ids.update({sm.product_id.id : {
                            'product_name' : sm.product_id.name,
                            'product_qty' : q * sign,
                            'original_remaining': original_remaining_qty,
                            'deducted_qty': analytic_line.deducted_quantity,
                            'process_qty' : analytic_line.process_qty,
                            'invoices_qty': analytic_line.invoices_qty, 
                            }
                        })
                else:
                    prod_ids_grouping = prod_ids[sm.product_id.id].copy()
                    prod_ids_grouping['product_qty'] += (q * sign)
                    prod_ids[sm.product_id.id] = prod_ids_grouping
                
            if prod_ids:
                for item in prod_ids.items():
                    if item[1]['original_remaining'] - item[1]['product_qty'] < 0:
                        error += ('the quantity of the product (%s) you process will be negative for the project. (qty remaining in project: %s, qty process: %s)\n' % (item[1]['product_name'],item[1]['original_remaining'],item[1]['product_qty']))

                    if (item[1]['process_qty'] + item[1]['product_qty']) < item[1]['deducted_qty']:
                        error += ('the quantity of the product (%s) you process will be less that deducted qty for the project. (qty process at project: %s, qty deducted: %s, qty after process : %s)\n' % (item[1]['product_name'],item[1]['process_qty'], item[1]['deducted_qty'], item[1]['process_qty'] + item[1]['product_qty']))
                    
                    if (item[1]['process_qty'] + item[1]['product_qty']) < item[1]['invoices_qty']:
                        error += ('the quantity of the product (%s) you process will be less that invoices qty for the project. (qty process at project: %s, qty invoices: %s, qty after process : %s)\n' % (item[1]['product_name'],item[1]['process_qty'], item[1]['deducted_qty'], item[1]['invoices_qty'] + item[1]['product_qty']))
                
            if error != '':
                msg = 'Cannot Process!! \n Reason : \n'
                msg += error
                raise osv.except_osv(_('Error!'), _(msg))
            processed_ids = []
            packops2 = spo_obj.search(cr, uid, [('picking_id', '=', picking.id)])
            for packop2 in packops2:
                spo_obj.unlink(cr, uid, [packop2], context=context)

            picking.do_prepare_partial()
            for op in picking.pack_operation_ids:
                pack_datas = {
                    'product_id': op.product_id.id,
                    'product_uom_id': op.product_uom_id.id,
                    'product_qty': op.product_qty,
                    'package_id': op.package_id.id,
                    'lot_id': op.lot_id.id,
                    'location_id': op.location_id.id,
                    'location_dest_id': op.location_dest_id.id,
                    'result_package_id': op.result_package_id.id,
                    'date': picking.date_done or time.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
                    'owner_id': op.owner_id.id,
                }
                if op.id:
                    op.write(pack_datas)
                    processed_ids.append(op.id)
    
            packops = spo_obj.search(cr, uid, ['&', ('picking_id', '=', picking.id), '!', ('id', 'in', processed_ids)])
            for packop in packops:
                packop.unlink()
    
            self.do_transfer_internal(cr, uid, [picking.id], context=context)

        return True
    
    def action_cancel2(self, cr, uid, ids, context=None):
        """ Changes picking state to cancel.
        @return: True
        """
        self.allow_cancel2(cr, uid, ids, context)
        analytic_line_obj = self.pool.get('analytic.quotation.line')
   
#         raise osv.except_osv(_('Error!'), _('You cannot duplicate the picking!'))
        for picking in self.browse(cr, uid, ids, context=context):
            if picking.state in ('cancel'):
                continue
            if not picking.project_id2:
                ids2 = [move.id for move in picking.move_lines]
                self.pool.get('stock.move').action_cancel(cr, uid, ids2, context)
                return self.write(cr, uid, ids, {'state': 'cancel', 'invoice_state': 'none'})
            
            prod_ids = {}
            mess = ''
            for sm in picking.move_lines:
                #product no found
                analytic_ids = analytic_line_obj.search(cr, uid, [('product_id', '=', sm.product_id.id), \
                                                                 ('analytic_id', '=', picking.project_id2.analytic_account_id.id), \
                                                                 ('type', '=', picking.department), \
                                                                 ], context=context)
                if not analytic_ids:
                    error += ('the product (%s) that entered is not list it at project : %s and department : %s. (No. %s) \n' % (sm.product_id.name, picking.project_id.name, picking.department, sm.no_stock_move))
                if analytic_ids:
                    analytic_line = analytic_line_obj.browse(cr, uid, analytic_ids[0], context=context)
                    sign = 1
                    if (sm.location_id.id == picking.picking_type_id.default_location_src_id.id) and  (sm.location_dest_id.id == picking.picking_type_id.default_location_dest_id.id):
                        sign = -1
                    elif (sm.location_id.id == picking.picking_type_id.default_location_dest_id.id) and  (sm.location_dest_id.id == picking.picking_type_id.default_location_src_id.id):
                        sign = 1
                    else:
                        raise osv.except_osv(_('Error!'), _('Wrong Location Selected!! \n Please Select the correct location for product: %s (No. %s)' %(sm.product_id.name, sm.no_stock_move)))
                    if (analytic_line.process_qty + (sm.product_qty * sign)) < analytic_line.deducted_quantity:
                        mess += ("The Internal Move Qty for department '%s' and product '%s' will be %s qty after cancel, " \
                                "and that qty is below to the processed deducted qty(%s). \n" % (picking.department, sm.product_id.name, (analytic_line.process_qty - sm.product_qty),analytic_line.deducted_quantity)) 
                    if (analytic_line.process_qty + (sm.product_qty * sign)) < analytic_line.invoices_qty:
                        mess += ("The Internal Move Qty for department '%s' and product '%s' will be %s qty after cancel, " \
                                "and that qty is below to the processed invoices qty(%s). \n" % (picking.department, sm.product_id.name, (analytic_line.process_qty - sm.product_qty),analytic_line.invoices_qty)) 
            if mess != '':
                raise osv.except_osv(_('Cannot Cancel this Internal Move!!'), _(mess))
            ids2 = [move.id for move in picking.move_lines]
            self.pool.get('stock.move').action_cancel(cr, uid, ids2, context)
            
        self.write(cr, uid, ids, {'state': 'cancel', 'invoice_state': 'none'})
        return True
    
    def write(self, cr, uid, ids, vals, context=None):
        gate_pass_state = False
        
        if 'gate_pass_state' in vals:
            gate_pass_state = vals['gate_pass_state']
        else:
            gate_pass_state = 'open'
        
        vals.update({'gate_pass_state': gate_pass_state})
            
        return super(stock_picking, self).write(cr, uid, ids, vals, context=context)
    
    def action_approved_gatepass(self, cr, uid, ids, context=None):
        for gp in self.browse(cr, uid, ids[0], context=context):
            self.write(cr, uid, gp.id, {'gate_pass_state':'approved', 'gate_pass_approver':uid, 'gate_pass_approver_time':time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
        return True
    
    def action_unapproved_gatepass(self, cr, uid, ids, context=None):
        for gp in self.browse(cr, uid, ids[0], context=context):
            self.write(cr, uid, gp.id, {'gate_pass_state':'open', 'gate_pass_approver':False, 'gate_pass_approver_time':False}, context=context)
        return True
    
    def get_parent_partner_id(self, partner_id):
        new_partner_id = False
        if partner_id.parent_id:
            new_partner_id = partner_id.parent_id
        if new_partner_id:
            new_partner_id = self.get_parent_partner_id(new_partner_id)
        else:
            new_partner_id = partner_id
        return new_partner_id

    def _get_real_partner(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        for rec in self.browse(cr, uid, ids, context=context):
            new_partner_id = self.get_parent_partner_id(rec.project_id2.analytic_account_id.partner_id)
            result[rec.id] = new_partner_id.id
        return result
    
    _columns = {
        'real_partner_id': fields.function(_get_real_partner, type='many2one', relation='res.partner', string='Partner'),
        'gate_pass': fields.boolean('Gate Pass'),
        'gate_pass_approver': fields.many2one('res.users', 'Gate Pass Approver'),
        'gate_pass_approver_time': fields.datetime(" Gate Pass Approval Time"),
        'gate_pass_state': fields.selection([('open','Waiting Approval'),('approved', 'Approved')],'Gate Pass State'),
        'requestor_id': fields.many2one('res.users', 'Requestor'),
        'remark' : fields.text('Remark', states={'confirmed':[('readonly',True)],
                                              'done':[('readonly',True)],
                                              'cancel':[('readonly',True)]}),
        'project_id2': fields.many2one('project.project', 'Contract / Analytic', states={'done': [('readonly', True)], 'cancel': [('readonly', True)], 'assigned': [('readonly', True)]}),
        'department':fields.selection([('shipyard','Shipyard'),
                                 ('mechanical','Mechanical'),
                                 ('electrical','Electrical'),
                                 ('welding_fabrication','Welding & Fabrication'),
                                 ('interior','Interior'),
                                 ('design','Design'),
                                 ('other_dept1','Other Dept1'),
                                 ('other_dept2','Other Dept2'),
                                 ('other_dept3','Other Dept3')
                                 ], 'Department',
                                states={'done': [('readonly', True)], 'cancel': [('readonly', True)], 'assigned': [('readonly', True)]}),
    }
    
    _defaults = {
        'gate_pass_state': 'open',
    }

class stock_move(osv.osv):

    _order = 'id'
    
    def _get_no(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        sm_ids = []
        sm_obj = self.pool.get('stock.move')
        for record in self.browse(cr, uid, ids, context=context):
            if record.picking_id:
                sm_ids = sm_obj.search(cr, uid, [('picking_id', '=', record.picking_id.id),('id', '<=', record.id)], order='id')
            result[record.id] = len(sm_ids)

        return result

    _inherit = "stock.move"

    _columns = {
        'no_stock_move': fields.function(_get_no, type='integer', string="No"),
    }

class stock_inventory(osv.osv):

    _inherit = "stock.inventory"
    
    def action_cancel_draft(self, cr, uid, ids, context=None):
        """ Cancels the stock move and change inventory state to draft.
        @return: True
        """
        for inv in self.browse(cr, uid, ids, context=context):
            if not inv.analytic_account_id.id: 
                self.pool.get('stock.move').action_cancel(cr, uid, [x.id for x in inv.move_ids], context=context)
                self.write(cr, uid, [inv.id], {'state': 'draft'}, context=context)
            else: 
                raise osv.except_osv(_('Error!'), _('cannot set to draft for this cancelled inventory adjustment, because this inventory adjustment generated from contract.'))
        return True
    
    _columns = {
        'analytic_account_id': fields.many2one('account.analytic.account', 'Contract'),
    }
    
class stock_inventory_line(osv.osv):

    _inherit = "stock.inventory.line"

    _columns = {
        'analytic_line_id': fields.many2one('analytic.quotation.line', 'Material'),
    }  
    
class analytic_quotation_line(osv.osv):

    _inherit = "analytic.quotation.line"
    
    def _calc_deducted_qty(self, cr, uid, ids, field_name, arg, context=None):
        result = {}
        
        stock_inventory_obj = self.pool.get('stock.inventory')
        stock_inventory_line_obj = self.pool.get('stock.inventory.line')
        analytic_quotation_line_obj = self.pool.get('analytic.quotation.line')
        
        analytic_quotation_line_ids = analytic_quotation_line_obj.search(cr, uid, [])
         
        if analytic_quotation_line_ids :
            for analytic_line in analytic_quotation_line_obj.browse(cr, uid, analytic_quotation_line_ids, context=context):   
                deducted_qty = 0
                stock_inventory_line_ids = stock_inventory_line_obj.search(cr, uid, [('analytic_line_id', '=', analytic_line.id)])
                for inv_line in stock_inventory_line_obj.browse(cr, uid, stock_inventory_line_ids, context=context):   
                    if inv_line.inventory_id.state == 'done':
                        deducted_qty += inv_line.product_qty
            
                result[analytic_line.id] = deducted_qty#analytic_line.process_qty - deducted_qty
                  
        return result
    
    _columns = {
        'deducted_quantity': fields.function(_calc_deducted_qty, type='float', string='Deducted Quantity'),
    }  